package classes;

import DAO.Configurator;
import DAO.DAOGeneric;
import DAO.DAOHospedagem;
import DAO.DAOHospede;
import DAO.DAOHotel;
import DAO.DAOQuarto;
import DAO.DAOReserva;
import Interface.Servidor;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author tony
 */
public class ServidorImplement extends UnicastRemoteObject implements Servidor {

    private static final long serialVersionUID = 1L;
    DAOHospede DAOhospede;
    DAOQuarto DAOquarto;
    DAOHotel DAOhotel;
    DAOHospedagem DAOhospedagem;
    DAOReserva DAOreserva;
    Configurator c = new Configurator();

    public ServidorImplement() throws RemoteException {
        super();

        //abrir todos os arquivos
        this.DAOhospede = new DAOHospede();
        this.DAOquarto = new DAOQuarto();
        this.DAOhotel = new DAOHotel();
        this.DAOhospedagem = new DAOHospedagem();
        this.DAOreserva = new DAOReserva();

        ServidorImplement.abrirArquivosLeitura(DAOhospede);
        ServidorImplement.abrirArquivosLeitura(DAOhospedagem);
        ServidorImplement.abrirArquivosLeitura(DAOquarto);
        ServidorImplement.abrirArquivosLeitura(DAOhotel);
        ServidorImplement.abrirArquivosLeitura(DAOreserva);
    }

    /**
     * 
     * @param nome
     * @param endereco
     * @param telefone
     * @param email
     * @return 
     */
    public synchronized boolean cadastrarHospede(String nome, String endereco, String telefone, String email) {
        //instanciação dos objetos
        Hospede hospede = new Hospede();

        //setagem dos atributos
        hospede.setId(DAOGeneric.getChave() + 1);
        hospede.setNome(nome);
        hospede.setEndereco(endereco);
        hospede.setEmail(email);
        hospede.setTelefone(telefone);
        hospede.setInadimplente(false);

        //metodo de gravar os dados
        DAOhospede.gravarDado(hospede);
        DAOhospede.abrirGravarArquivo();
        DAOhospede.persistirDados();
        c.gravarChave(DAOGeneric.getChave());
        DAOhospede.fecharArquivoEscrito();

        System.out.println("Cliente cadastrado!");

        return true;
    }

    /**
     * 
     * @param idHospede
     * @param idQuarto
     * @param idHotel
     * @param data
     * @return
     * @throws RemoteException 
     */
    public synchronized boolean cadastrarHospedagem(Integer idHospede, Integer idQuarto, Integer idHotel, String data) throws RemoteException {
        //instanciação dos objetos
        Hospedagem hospedagem = new Hospedagem();

        //recupera um hospede pelo id
        Hospede hospede = (Hospede) DAOhospede.lerDadoPorIndice(idHospede);
        //recupera um hotel pelo id
        Hotel hotel = (Hotel) DAOhotel.lerDadoPorIndice(idHotel);
        //recupera um quarto pelo id
        Quarto quarto = (Quarto) DAOquarto.lerDadoPorIndice(idQuarto);

        //verifica se o quarto esta sendo usado
        if (verificarDisponibilidadeHospedagem(idHotel, idQuarto, idHospede)) {
            //verifica se existe uma reserva para o quarto naquela data
            if (verificarDisponibilidadeReserva(idHotel, idQuarto, idHospede, data)) {
                //verifica se o hospede deve algo
                if (!verificarInadimplencia(idHospede)) {

                    //seta o hospede como inadimplente
                    hospede.setInadimplente(true);

                    //setagem dos atributos
                    hospedagem.setId(DAOGeneric.getChave() + 1);
                    hospedagem.setData(data);
                    hospedagem.setHospede(hospede);
                    hospedagem.setHotel(hotel);
                    hospedagem.setQuarto(quarto);

                    //metodo de gravar os dados
                    DAOhospedagem.gravarDado(hospedagem);

                    atualizarArquivos();

                    System.out.println("Hospedagem cadastrada!");
                    return true;
                } else {
                    System.out.println("Hospedagem nao cadastrada, por que deve a empresa!");
                    return false;
                }
            } else {
                System.out.println("Hospedagem nao cadastrada, pois o mesmo já esta reservado para outro!");
                return false;
            }
        } else {
            System.out.println("Hospedagem nao cadastrada, pois o mesmo já esta ocupado!");
            return false;
        }
    }

    public synchronized static void abrirArquivosLeitura(DAOGeneric dao) {
        dao.abrirLerArquivo();
        dao.lerDados();
        dao.fecharArquivoLido();
    }

    public synchronized static void abrirArquivosGravacao(DAOGeneric dao) {
        dao.abrirGravarArquivo();
        dao.fecharArquivoEscrito();
    }

    public synchronized Hospedagem listarHospedagem(Integer idHospedagem) throws RemoteException {
        return (Hospedagem) DAOhospedagem.lerDadoPorIndice(idHospedagem);
    }

    public synchronized Hospede listarHospede(Integer idHospede) throws RemoteException {
        return (Hospede) DAOhospede.lerDadoPorIndice(idHospede);
    }

    public synchronized Hotel listarHotel(Integer idHotel) throws RemoteException {
        return (Hotel) DAOhotel.lerDadoPorIndice(idHotel);
    }

    public synchronized Quarto listarQuarto(Integer idQuarto) throws RemoteException {
        return (Quarto) DAOquarto.lerDadoPorIndice(idQuarto);
    }

    public synchronized List listarHospedagens() throws RemoteException {
        HashMap hospe = (HashMap) DAOhospedagem.getDados();
        List hoped = new ArrayList<Hospedagem>();

        Collection c = hospe.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            hoped.add(itr.next());
        }
        return hoped;

    }

    public synchronized List listarHospedes() throws RemoteException {
        HashMap hospe = (HashMap) DAOhospede.getDados();
        List hoped = new ArrayList<Hospede>();

        Collection c = hospe.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            hoped.add(itr.next());
        }
        return hoped;
    }

    public synchronized List listarHoteis() throws RemoteException {
        HashMap hot = (HashMap) DAOhotel.getDados();
        List hote = new ArrayList<Hotel>();

        Collection c = hot.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            hote.add(itr.next());
        }
        return hote;
    }

    public synchronized List listarQuartos() throws RemoteException {
        HashMap quar = (HashMap) DAOquarto.getDados();
        List quart = new ArrayList<Quarto>();

        Collection c = quar.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            quart.add(itr.next());
        }
        return quart;
    }

    public synchronized List listarReservas() throws RemoteException {
        HashMap hot = (HashMap) DAOreserva.getDados();
        List hote = new ArrayList<Reserva>();

        Collection c = hot.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            hote.add(itr.next());
        }
        return hote;
    }

    public synchronized boolean cadastrarReserva(Integer idHotel, Integer idQuarto, Integer idHospede, String data) throws RemoteException {
        //verifica se o quarto esta reservado
        if (verificarDisponibilidadeReserva(idHotel, idQuarto, idHospede, data)) {
            //verifica se o hospede deve a empresa 
            if (!verificarInadimplencia(idHospede)) {
                //recupera um hospede pelo id
                Hospede hospede = (Hospede) DAOhospede.lerDadoPorIndice(idHospede);
                Hotel hotel = (Hotel) DAOhotel.lerDadoPorIndice(idHotel);
                Quarto quarto = (Quarto) DAOquarto.lerDadoPorIndice(idQuarto);

                Reserva r = new Reserva(DAOGeneric.getChave() + 1, quarto, hospede, data, hotel);
                DAOreserva.gravarDado(r);
                atualizarArquivos();
                System.out.println("reserva cadastrada!");
                return true;
            } else {
                System.out.println("reserva não cadastrada, pois o usuario deve a empresa!");
                return false;
            }
        } else {
            System.out.println("reserva não cadastrada, pois já existe reserva para esse dia!");
            return false;
        }
    }

    public synchronized boolean verificarDisponibilidadeReserva(Integer idHotel, Integer idQuarto, Integer idHospede, String data) throws RemoteException {
        List reservas = listarReservas();
        Iterator itr = reservas.iterator();
        while (itr.hasNext()) {
            Reserva r = (Reserva) itr.next();
            System.out.println("Data dos cadatros ->" + r.getHotel() + " / data a ser testar ->" + data);
            if (r.getHotel() != null) {
                System.out.println("Data dos cadatros ->" + r.getData() + " / data a ser testar ->" + data);
                if ((r.getHotel().getId() == idHotel) && (r.getQuarto().getId() == idQuarto) && (r.getData().equals(data))) {
                    return false;
                }
            }
        }
        return true;
    }

    public synchronized boolean verificarDisponibilidadeHospedagem(Integer idHotel, Integer idQuarto, Integer idHospede) throws RemoteException {
        HashMap hospedagens = (HashMap) DAOhospedagem.getDados();
        Collection c = hospedagens.values();
        Iterator itr = c.iterator();
        Date data = new Date();
        SimpleDateFormat formatador = new SimpleDateFormat("dd/MM/yyyy");
        while (itr.hasNext()) {
            Hospedagem r = (Hospedagem) itr.next();
            if (r.getHotel() != null) {
                if ((r.getHospede().isInadimplente()) && (r.getHotel().getId() == idHotel) && (r.getQuarto().getId() == idQuarto) && (r.getData().equals(formatador.format(data)))) {
                    return false;
                }
            }
        }
        return true;
    }

    public synchronized Reserva listarReserva(Integer idReserva) throws RemoteException {
        return (Reserva) DAOreserva.lerDadoPorIndice(idReserva);
    }

    public synchronized boolean verificarInadimplencia(Integer idHospede) throws RemoteException {
        HashMap hospe = (HashMap) DAOhospedagem.getDados();
        Collection c = hospe.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            Hospedagem hp = (Hospedagem) itr.next();
            if (hp.getHospede() != null) {
                if (hp.getHospede().getId() == idHospede) {
                    if (hp.getHospede().isInadimplente()) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public synchronized boolean pagarConta(Integer idHospede, Integer idHospedagem) throws RemoteException {
        //recupera um hospedagem pelo id
        Hospedagem hospedagem = (Hospedagem) DAOhospedagem.lerDadoPorIndice(idHospedagem);

        if (hospedagem.getHospede().getId() == idHospede) {
            hospedagem.getHospede().setInadimplente(false);
            System.out.println(DAOhospedagem.lerDadoPorIndice(idHospedagem));
            return true;
        }
        return false;
    }

    public synchronized List listarHospedagensPorHospede(Integer id) throws RemoteException {
        HashMap hospe = (HashMap) DAOhospedagem.getDados();
        List hoped = new ArrayList<Hospedagem>();

        Collection c = hospe.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            Hospedagem h = (Hospedagem) itr.next();
            if (h.getHospede() != null) {
                if (h.getHospede().getId() == id) {
                    hoped.add(h);
                }
            }
        }
        return hoped;
    }

    public synchronized List ListarHospedagensPorHospede_naoPago(Integer id) throws RemoteException {
        HashMap hospe = (HashMap) DAOhospedagem.getDados();
        List hoped = new ArrayList<Hospedagem>();
        long maior = 0;
        Collection c = hospe.values();
        Iterator itr = c.iterator();
        Hospedagem ultima = null;
        while (itr.hasNext()) {
            Hospedagem h = (Hospedagem) itr.next();
            if (h.getHospede() != null) {
                if (h.getHospede().isInadimplente() && (h.getHospede().getId() == id)) {
                    if (maior < h.getId()) {
                        ultima = h;
                        maior = h.getId();
                    }
                }
            }
        }
        hoped.add(ultima);
        return hoped;
    }

    public synchronized List listarHospedesInadimplentes() throws RemoteException {
        HashMap hospe = (HashMap) DAOhospede.getDados();
        List hoped = new ArrayList<Hospede>();
        Collection c = hospe.values();
        Iterator itr = c.iterator();
        while (itr.hasNext()) {
            Hospede h = (Hospede) itr.next();
            if (h.isInadimplente()) {
                hoped.add(h);
            }
        }
        System.out.println(hoped);
        return hoped;
    }

    public synchronized boolean prolongarHospedagem(Integer idHospede) throws RemoteException {

        //recupera um hospede pelo id
        HashMap hospedagens = (HashMap) DAOhospedagem.getDados();
        Integer idHotel = null;
        Integer idQuarto = null;

        //Date data = new Date();
        SimpleDateFormat formatador = new SimpleDateFormat("dd/MM/yyyy");
        Calendar data = new GregorianCalendar();
        data.add(Calendar.DAY_OF_MONTH, 1);
        String dt = formatador.format(data.getTime());
        Collection c = hospedagens.values();
        Iterator itr = c.iterator();
        Hospedagem hop = null;
        while (itr.hasNext()) {
            Hospedagem h = (Hospedagem) itr.next();
            if (h.getHospede() != null) {
                if (h.getHospede().getId() == idHospede) {
                    hop = h;
                }
            }
        }

        idHotel = hop.getHotel().getId();
        idQuarto = hop.getQuarto().getId();

        //verifica se existe uma reserva para o quarto naquela data
        if (verificarDisponibilidadeReserva(idHotel, idQuarto, idHospede, dt)) {
            //instanciação dos objetos
            Hospedagem hospedagem = new Hospedagem();

            //recupera um hospede pelo id
            Hospede hospede = (Hospede) DAOhospede.lerDadoPorIndice(idHospede);
            //recupera um hotel pelo id
            Hotel hotel = (Hotel) DAOhotel.lerDadoPorIndice(idHotel);
            //recupera um quarto pelo id
            Quarto quarto = (Quarto) DAOquarto.lerDadoPorIndice(idQuarto);

            //seta o hospede como inadimplente
            hospede.setInadimplente(true);

            //setagem dos atributos
            hospedagem.setId(DAOGeneric.getChave() + 1);
            hospedagem.setData(dt);
            hospedagem.setHospede(hospede);
            hospedagem.setHotel(hotel);
            hospedagem.setQuarto(quarto);

            //metodo de gravar os dados
            DAOhospedagem.gravarDado(hospedagem);

            atualizarArquivos();

            System.out.println("Re-hospedagem cadastrada!");
            return true;
        } else {
            System.out.println("Hospedagem nao cadastrada, pois o mesmo já esta reservado para outro!");
            return false;
        }
    }

    public void atualizarArquivos() {
        DAOhospedagem.abrirGravarArquivo();
        DAOhospede.abrirGravarArquivo();
        DAOhotel.abrirGravarArquivo();
        DAOquarto.abrirGravarArquivo();
        DAOreserva.abrirGravarArquivo();

        DAOhospedagem.persistirDados();
        DAOhospede.persistirDados();
        DAOhotel.persistirDados();
        DAOquarto.persistirDados();
        DAOreserva.persistirDados();

        c.gravarChave(DAOGeneric.getChave());



    }

    public synchronized List listarQuartosPorHotel(Integer id) throws RemoteException {
        List<Quarto> q = new ArrayList<Quarto>();
        System.out.println(id);
        Hotel hotel = (Hotel) DAOhotel.lerDadoPorIndice(id);

        return hotel.getQuartos();
    }

    public synchronized boolean cadastrarHotel(String nome, String gerente, String endereco) throws RemoteException {
        //instanciação dos objetos
        List quart = new ArrayList<Quarto>();
        quart.add(new Quarto(20000, null, null, false, null, null));
        Hotel hotel = new Hotel();
        hotel.setNome(nome);
        hotel.setEndereco(endereco);
        hotel.setGerente(gerente);
        hotel.setId(DAOGeneric.getChave() + 1);
        hotel.setQuartos(quart);
        DAOhotel.gravarDado(hotel);
        atualizarArquivos();

        return true;
    }

    public synchronized boolean cadastrarQuatro(Integer idHotel, String numero, String andar) throws RemoteException {
        Quarto q = new Quarto();
        //recupera um hotel pelo id
        Hotel h = (Hotel) DAOhotel.lerDadoPorIndice(idHotel);

        List<Quarto> quartos = h.getQuartos();

        System.out.println("quartos -> " + h.getQuartos());

        q.setAndar(andar);
        q.setId(DAOGeneric.getChave() + 1);
        q.setNumero(numero);
        q.setOcupado(false);

        DAOquarto.gravarDado(q);

        atualizarArquivos();

        quartos.add(q);
        h.setQuartos(quartos);

        return true;
    }

    public synchronized boolean deletarHospede(Integer idHospede) throws RemoteException {
        Hospede hospede = (Hospede) DAOhospede.lerDadoPorIndice(idHospede);

        if (hospede != null) {
            HashMap hospedes = (HashMap) DAOhospede.getDados();
            hospedes.remove(idHospede);
            atualizarArquivos();
            return true;
        } else {
            return false;
        }
    }

    public synchronized boolean deletarHospedagem(Integer idHospedagem) throws RemoteException {
        Hospedagem hospedagem = (Hospedagem) DAOhospedagem.lerDadoPorIndice(idHospedagem);

        if (hospedagem != null) {
            HashMap hospedagens = (HashMap) DAOhospedagem.getDados();
            hospedagens.remove(idHospedagem);
            atualizarArquivos();
            return true;
        } else {
            return false;
        }
    }

    public synchronized boolean deletarReserva(Integer idReserva) throws RemoteException {
        Reserva reserva = (Reserva) DAOreserva.lerDadoPorIndice(idReserva);

        if (reserva != null) {
            HashMap reservas = (HashMap) DAOreserva.getDados();
            reservas.remove(idReserva);
            atualizarArquivos();
            return true;
        } else {
            return false;
        }
    }
}
